{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to atomman: Box class\n",
    "\n",
    "__Lucas M. Hale__, [lucas.hale@nist.gov](mailto:lucas.hale@nist.gov?Subject=ipr-demo), _Materials Science and Engineering Division, NIST_.\n",
    "    \n",
    "[Disclaimers](http://www.nist.gov/public_affairs/disclaimer.cfm) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Introduction <a id='section1'></a>\n",
    "\n",
    "The atomman.Box class represents a generic parallelepiped that can be used as a simulation box/cell allowing for translational symmetry in all three dimensions.  The underlying data structure consists of three 3D vectors:\n",
    "\n",
    "- **avect** is the Cartesian vector associated with the Box's a lattice vector.\n",
    "\n",
    "- **bvect** is the Cartesian vector associated with the Box's b lattice vector.\n",
    "\n",
    "- **cvect** is the Cartesian vector associated with the Box's c lattice vector.\n",
    "\n",
    "- **origin** is the Cartesian position vector for the Box's origin.  The positions of the Box's eight corners are given by adding combinations of avect, bvect and cvect to the origin."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Library Imports**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atomman version = 1.4.0\n",
      "Notebook executed on 2021-08-03\n"
     ]
    }
   ],
   "source": [
    "# Standard Python libraries\n",
    "import datetime\n",
    "\n",
    "# http://www.numpy.org/\n",
    "import numpy as np\n",
    "\n",
    "# https://github.com/usnistgov/atomman\n",
    "import atomman as am\n",
    "import atomman.unitconvert as uc\n",
    "\n",
    "# Show atomman version\n",
    "print('atomman version =', am.__version__)\n",
    "\n",
    "# Show date of Notebook execution\n",
    "print('Notebook executed on', datetime.date.today())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Create a default box with vects that are normal unit vectors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 1.000,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  1.000,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  1.000]\n",
      "origin = [ 0.000,  0.000,  0.000]\n"
     ]
    }
   ],
   "source": [
    "box = am.Box()\n",
    "\n",
    "print(box)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Box parameters <a id='section2'></a>\n",
    "\n",
    "The Box class supports a number of different parameters to represent the underlying box. All of these parameters can be fetched as class attributes.\n",
    "\n",
    "- **avect, bvect, cvect** are the Cartesian vectors associated with the Box's lattice vectors.\n",
    "\n",
    "- **origin** is the Cartesian position vector for the Box's origin.\n",
    "\n",
    "- **vects** is a 3x3 array containing [avect, bvect, cvect].\n",
    "\n",
    "- **a, b, c** are the Box's lattice parameters (magnitudes of avect, bvect, cvect, respectively).\n",
    "\n",
    "- **alpha, beta, gamma** are the Box's lattice angles in degrees.\n",
    "\n",
    "- **xlo, xhi, ylo, yhi, zlo, zhi** are the LAMMPS hi/lo box dimensions.\n",
    "\n",
    "- **lx, ly, lz** are the LAMMPS box dimensions (lx = xhi - xlo, etc.)\n",
    "\n",
    "- **xy, xz, yz** are the LAMMPS box tilt factors.\n",
    "\n",
    "- **volume** is the box's volume (added version 1.2.5).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "box.avect -> [1. 0. 0.]\n",
      "box.bvect -> [0. 1. 0.]\n",
      "box.cvect -> [0. 0. 1.]\n",
      "\n",
      "box.origin -> [0. 0. 0.]\n",
      "\n",
      "box.vects ->\n",
      "[[1. 0. 0.]\n",
      " [0. 1. 0.]\n",
      " [0. 0. 1.]]\n",
      "\n",
      "box.a -> 1.0\n",
      "box.b -> 1.0\n",
      "box.c -> 1.0\n",
      "box.alpha -> 90.0\n",
      "box.beta  -> 90.0\n",
      "box.gamma -> 90.0\n",
      "\n",
      "box.xlo -> 0.0\n",
      "box.xhi -> 1.0\n",
      "box.ylo -> 0.0\n",
      "box.yhi -> 1.0\n",
      "box.zlo -> 0.0\n",
      "box.zhi -> 1.0\n",
      "box.lx -> 1.0\n",
      "box.ly -> 1.0\n",
      "box.lz -> 1.0\n",
      "box.xy -> 0.0\n",
      "box.xz -> 0.0\n",
      "box.yz -> 0.0\n",
      "\n",
      "box.volume -> 1.0\n"
     ]
    }
   ],
   "source": [
    "# Individual box vectors\n",
    "print('box.avect ->', box.avect)\n",
    "print('box.bvect ->', box.bvect)\n",
    "print('box.cvect ->', box.cvect)\n",
    "print()\n",
    "\n",
    "# Box origin position\n",
    "print('box.origin ->', box.origin)\n",
    "print()\n",
    "\n",
    "# Array of box vectors\n",
    "print('box.vects ->')\n",
    "print(box.vects)\n",
    "print()\n",
    "\n",
    "# Crystal lattice parameters\n",
    "print('box.a ->', box.a)\n",
    "print('box.b ->', box.b)\n",
    "print('box.c ->', box.c)\n",
    "print('box.alpha ->', box.alpha)\n",
    "print('box.beta  ->', box.beta)\n",
    "print('box.gamma ->', box.gamma)\n",
    "print()\n",
    "\n",
    "# LAMMPS parameters\n",
    "print('box.xlo ->', box.xlo)\n",
    "print('box.xhi ->', box.xhi)\n",
    "print('box.ylo ->', box.ylo)\n",
    "print('box.yhi ->', box.yhi)\n",
    "print('box.zlo ->', box.zlo)\n",
    "print('box.zhi ->', box.zhi)\n",
    "print('box.lx ->', box.lx)\n",
    "print('box.ly ->', box.ly)\n",
    "print('box.lz ->', box.lz)\n",
    "print('box.xy ->', box.xy)\n",
    "print('box.xz ->', box.xz)\n",
    "print('box.yz ->', box.yz)\n",
    "print()\n",
    "\n",
    "# Box volume\n",
    "print('box.volume ->', box.volume)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Initializing and setting Box parameters <a id='section3'></a>\n",
    "\n",
    "Only a few of the parameters listed in [Section #2](#section2) can be directly set.  This is done as setting some of the parameters independent of others can lead to ambiguous answers.  For better control, set() functions are defined that allow for the setting of complete parameter sets for defining the box."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1. Direct setting box vects and origin\n",
    "\n",
    "Only vects and origin can be directly set."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 3.984,  2.105,  3.954]\n",
      "bvect =  [ 2.501,  1.440,  1.008]\n",
      "cvect =  [ 0.239,  0.756,  3.879]\n",
      "origin = [ 0.138,  0.565,  0.913]\n"
     ]
    }
   ],
   "source": [
    "# Set avect, bvect, cvect and origin with random vectors\n",
    "box.vects = 4 * np.random.rand(3,3)\n",
    "box.origin = np.random.rand(3)\n",
    "print(box)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2. Box initializing and Box.set() method \n",
    "\n",
    "A new Box can be initialized or an existing Box can be changed using the Box.set() method by using one of the following sets of parameters (optional terms in parenthesis):\n",
    "\n",
    "- vects (and origin)\n",
    "\n",
    "- avect, bvect, cvect (and origin)\n",
    "\n",
    "- a, b, c, (alpha, beta, gamma and origin)\n",
    "\n",
    "- xlo, xhi, ylo, yhi, zlo, zhi, (xy, xz and yz)\n",
    "\n",
    "- lx, ly, lz, (xy, xz, yz, and origin)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 1.000,  2.000,  3.000]\n",
      "bvect =  [ 2.000,  3.000,  1.000]\n",
      "cvect =  [ 3.000,  1.000,  2.000]\n",
      "origin = [ 0.000,  0.000,  0.000]\n"
     ]
    }
   ],
   "source": [
    "# Use set with vects (default origin is [0,0,0])\n",
    "box.set(vects=[[1,2,3], [2,3,1], [3,1,2]])\n",
    "print(box)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 3.200,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  3.200,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  3.200]\n",
      "origin = [ 0.000,  0.000,  0.000]\n"
     ]
    }
   ],
   "source": [
    "# Use set with avect, bvect, cvect (default origin is [0,0,0])\n",
    "box.set(avect=[3.2, 0.0, 0.0], bvect=[0.0, 3.2, 0.0], cvect=[0.0, 0.0, 3.2])\n",
    "print(box)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 4.300,  0.000,  0.000]\n",
      "bvect =  [ 0.000,  3.200,  0.000]\n",
      "cvect =  [ 0.000, -2.770,  7.612]\n",
      "origin = [ 0.000,  0.000,  0.000]\n",
      "\n",
      "box.a -> 4.3\n",
      "box.b -> 3.2\n",
      "box.c -> 8.1\n",
      "box.alpha -> 110.0\n",
      "box.beta  -> 90.0\n",
      "box.gamma -> 90.0\n"
     ]
    }
   ],
   "source": [
    "# Use set with a, b, c and alpha (default angles are 90, origin is [0,0,0])\n",
    "box.set(a=4.3, b=3.2, c=8.1, alpha=110)\n",
    "print(box)\n",
    "print()\n",
    "\n",
    "# Show that box definition coincides with parameters set\n",
    "print('box.a ->', box.a)\n",
    "print('box.b ->', box.b)\n",
    "print('box.c ->', box.c)\n",
    "print('box.alpha ->', box.alpha)\n",
    "print('box.beta  ->', box.beta)\n",
    "print('box.gamma ->', box.gamma)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [ 6.000,  0.000,  0.000]\n",
      "bvect =  [ 0.500,  7.100,  0.000]\n",
      "cvect =  [ 0.000,  0.000,  3.000]\n",
      "origin = [-1.000, -2.100,  0.100]\n",
      "\n",
      "box.xlo -> -1.0\n",
      "box.xhi -> 5.0\n",
      "box.ylo -> -2.1\n",
      "box.yhi -> 5.0\n",
      "box.zlo -> 0.1\n",
      "box.zhi -> 3.1\n",
      "box.xy -> 0.5\n",
      "box.xz -> 0.0\n",
      "box.yz -> 0.0\n"
     ]
    }
   ],
   "source": [
    "# Use set with xlo, xhi, ylo, yhi, zlo, zhi and xy (default tilts are 0)\n",
    "box.set(xlo=-1, xhi=5, ylo=-2.1, yhi=5, zlo=0.1, zhi=3.1, xy=0.5)\n",
    "print(box)\n",
    "print()\n",
    "\n",
    "# Show that box definition coincides with parameters set\n",
    "print('box.xlo ->', box.xlo)\n",
    "print('box.xhi ->', box.xhi)\n",
    "print('box.ylo ->', box.ylo)\n",
    "print('box.yhi ->', box.yhi)\n",
    "print('box.zlo ->', box.zlo)\n",
    "print('box.zhi ->', box.zhi)\n",
    "print('box.xy ->', box.xy)\n",
    "print('box.xz ->', box.xz)\n",
    "print('box.yz ->', box.yz)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [42.000,  0.000,  0.000]\n",
      "bvect =  [ 0.000, 57.000,  0.000]\n",
      "cvect =  [15.000,  0.000, 112.000]\n",
      "origin = [ 1.000,  2.000,  3.000]\n",
      "\n",
      "box.lx -> 42.0\n",
      "box.ly -> 57.0\n",
      "box.lz -> 112.0\n",
      "box.xy -> 0.0\n",
      "box.xz -> 15.0\n",
      "box.yz -> 0.0\n"
     ]
    }
   ],
   "source": [
    "# Use set with lx, ly, lz and xz (default tilts are 0, origin is [0,0,0])\n",
    "box.set(lx=42, ly=57, lz=112, xz=15, origin=[1,2,3])\n",
    "print(box)\n",
    "print()\n",
    "\n",
    "# Show that box definition coincides with parameters set\n",
    "print('box.lx ->', box.lx)\n",
    "print('box.ly ->', box.ly)\n",
    "print('box.lz ->', box.lz)\n",
    "print('box.xy ->', box.xy)\n",
    "print('box.xz ->', box.xz)\n",
    "print('box.yz ->', box.yz)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3. Crystal family static methods\n",
    "\n",
    "*Added version 1.2.5*\n",
    "\n",
    "There are also methods for each of the seven crystal families that are convenient for the construction of unit cell systems in standard representations:\n",
    "\n",
    "- **cubic(a)**: $a = b = c; \\alpha = \\beta = \\gamma = 90^\\circ$\n",
    "\n",
    "- **hexagonal(a, c)**: $a = b \\ne c; \\alpha = \\beta = 90^\\circ; \\gamma = 120^\\circ$\n",
    "\n",
    "- **tetragonal(a, c)**: $a = b \\ne c; \\alpha = \\beta = \\gamma = 90^\\circ$\n",
    "\n",
    "- **trigonal(a, alpha)**: $a = b = c; \\alpha = \\beta = \\gamma < 120^\\circ$\n",
    "\n",
    "- **orthorhombic(a, b, c)**: $a \\ne b \\ne c; \\alpha = \\beta = \\gamma = 90^\\circ$\n",
    "\n",
    "- **monoclinic(a, b, c, beta)**: $a \\ne b \\ne c; \\alpha = \\gamma = 90^\\circ; \\beta > 90^\\circ$\n",
    "\n",
    "- **triclinic(a, b, c, alpha, beta, gamma)**: $a \\ne b \\ne c; \\alpha \\ne \\beta \\ne \\gamma$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "am.Box.cubic(4.25) ->\n",
      "box.a -> 4.25\n",
      "box.b -> 4.25\n",
      "box.c -> 4.25\n",
      "box.alpha -> 90.0\n",
      "box.beta  -> 90.0\n",
      "box.gamma -> 90.0\n"
     ]
    }
   ],
   "source": [
    "print('am.Box.cubic(4.25) ->')\n",
    "box = am.Box.cubic(4.25)\n",
    "print('box.a ->', box.a)\n",
    "print('box.b ->', box.b)\n",
    "print('box.c ->', box.c)\n",
    "print('box.alpha ->', box.alpha)\n",
    "print('box.beta  ->', box.beta)\n",
    "print('box.gamma ->', box.gamma)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "am.Box.hexagonal(3.12, 5.14) ->\n",
      "box.a -> 3.12\n",
      "box.b -> 3.12\n",
      "box.c -> 5.14\n",
      "box.alpha -> 90.0\n",
      "box.beta  -> 90.0\n",
      "box.gamma -> 119.99999999999999\n"
     ]
    }
   ],
   "source": [
    "print('am.Box.hexagonal(3.12, 5.14) ->')\n",
    "box = am.Box.hexagonal(3.12, 5.14)\n",
    "print('box.a ->', box.a)\n",
    "print('box.b ->', box.b)\n",
    "print('box.c ->', box.c)\n",
    "print('box.alpha ->', box.alpha)\n",
    "print('box.beta  ->', box.beta)\n",
    "print('box.gamma ->', box.gamma)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. LAMMPS-compatible Boxes <a id='section4'></a>\n",
    "\n",
    "For boxes to be compatible with LAMMPS, they have to adhere to the following conditions:\n",
    "\n",
    "- avect, bvect, cvect are right-handed.\n",
    "\n",
    "- Only certain components of the lattice vectors are allowed to be non-zero:\n",
    "\n",
    "        avect = [lx, 0.0, 0.0]\n",
    "        bvect = [xy,  ly, 0.0]\n",
    "        cvect = [xz,  yz,  lz]\n",
    "        \n",
    "- The tilt factors are limited to being between -1/2 and 1/2 the corresponding length terms. \n",
    "\n",
    "The first two conditions are automatically adhered to if the box is set with LAMMPS terms or crystal lattice parameters, but may not be true if the box was set using the crystal vectors. The third condition is not checked by atomman. Large tilt factors are allowed by LAMMPS if the \"box tilt large\" command is used."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1. Box.is_lammps_norm()\n",
    "\n",
    "This function returns True if the Box is compatible with the first two LAMMPS condtions and False otherwise. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "box.is_lammps_norm() -> True\n"
     ]
    }
   ],
   "source": [
    "# The current box was defined with LAMMPS parameters, therefore is compatible\n",
    "print('box.is_lammps_norm() ->', box.is_lammps_norm())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "box.is_lammps_norm() -> False\n"
     ]
    }
   ],
   "source": [
    "# Define a non-lammps compatible box using set(avect, bvect, cvect)\n",
    "box.set(avect=[10, 0.1, 0.0], bvect=[0.2, 9.0, 0.0], cvect=[-0.2, 0.5, 14])\n",
    "\n",
    "print('box.is_lammps_norm() ->', box.is_lammps_norm())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Trying to access LAMMPS box parameters for incompatible boxes will issue an error."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "AssertionError: Box is not normalized for LAMMPS style parameters\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    box.lx\n",
    "except AssertionError as e:\n",
    "    print('AssertionError:', e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Box model <a id='section5'></a>\n",
    "\n",
    "*Added version 1.2.7*\n",
    "\n",
    "A JSON/XML equivalent data model representation of the Box object can be generated using the model() method. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\"box\": {\"avect\": {\"value\": [10.0, 0.1, 0.0], \"unit\": \"angstrom\"}, \"bvect\": {\"value\": [0.2, 9.0, 0.0], \"unit\": \"angstrom\"}, \"cvect\": {\"value\": [-0.2, 0.5, 14.0], \"unit\": \"angstrom\"}, \"origin\": {\"value\": [0.0, 0.0, 0.0], \"unit\": \"angstrom\"}}}\n",
      "\n",
      "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
      "<box><avect><value>10.0</value><value>0.1</value><value>0.0</value><unit>angstrom</unit></avect><bvect><value>0.2</value><value>9.0</value><value>0.0</value><unit>angstrom</unit></bvect><cvect><value>-0.2</value><value>0.5</value><value>14.0</value><unit>angstrom</unit></cvect><origin><value>0.0</value><value>0.0</value><value>0.0</value><unit>angstrom</unit></origin></box>\n"
     ]
    }
   ],
   "source": [
    "model = box.model()\n",
    "print(model.json())\n",
    "print()\n",
    "print(model.xml())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The units of length used in the model can be set using the 'length_unit' parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\"box\": {\"avect\": {\"value\": [1.0, 0.01, 0.0], \"unit\": \"nm\"}, \"bvect\": {\"value\": [0.02, 0.9, 0.0], \"unit\": \"nm\"}, \"cvect\": {\"value\": [-0.02, 0.05, 1.4], \"unit\": \"nm\"}, \"origin\": {\"value\": [0.0, 0.0, 0.0], \"unit\": \"nm\"}}}\n"
     ]
    }
   ],
   "source": [
    "model = box.model(length_unit='nm')\n",
    "print(model.json())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Any stored model information can then be reloaded in as a Box object by passing the 'model' parameter to either the class initializer or the model() method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [10.000,  0.100,  0.000]\n",
      "bvect =  [ 0.200,  9.000,  0.000]\n",
      "cvect =  [-0.200,  0.500, 14.000]\n",
      "origin = [ 0.000,  0.000,  0.000]\n"
     ]
    }
   ],
   "source": [
    "print(am.Box(model=model))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "avect =  [10.000,  0.100,  0.000]\n",
      "bvect =  [ 0.200,  9.000,  0.000]\n",
      "cvect =  [-0.200,  0.500, 14.000]\n",
      "origin = [ 0.000,  0.000,  0.000]\n"
     ]
    }
   ],
   "source": [
    "box.model(model=model)\n",
    "print(box)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. Inside/outside <a id='section6'></a>\n",
    "\n",
    "*Added version 1.3.0*\n",
    "\n",
    "The Box is treated as a regional shape object (see [3.3._Region_selectors.html](3.3._Region_selectors.html)) and has methods inside() and outside() that indicate whether any 3D coordinate(s) are located inside or outside the shape."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[3.50935711e-04 8.43534481e+00 7.56186733e+00]\n",
      " [7.68417174e+00 1.44018251e+00 3.82031142e+00]\n",
      " [5.42692419e+00 5.34775862e+00 8.36842195e+00]\n",
      " [5.02098822e-01 7.29699620e+00 5.73972206e+00]\n",
      " [5.49586909e+00 3.41205627e+00 2.40458800e+00]\n",
      " [1.90197071e+00 6.01091414e+00 4.15105154e+00]\n",
      " [7.60738650e+00 1.13225840e+00 7.60973322e-01]\n",
      " [2.68222970e+00 1.90518002e+00 3.87149087e+00]\n",
      " [2.32293387e+00 6.81898691e+00 4.46305318e-01]\n",
      " [2.42944318e-01 1.24921142e+00 3.41695583e+00]\n",
      " [4.81760739e+00 3.87201936e+00 4.61687957e-01]\n",
      " [8.80313374e+00 6.62335023e+00 1.14546269e+00]\n",
      " [6.85628854e+00 2.01130575e+00 9.82021815e-01]\n",
      " [2.86122074e+00 2.70360586e+00 8.16799600e+00]\n",
      " [5.42580903e+00 9.51393606e+00 7.15510070e+00]\n",
      " [7.41785970e+00 5.59991385e+00 2.16687590e+00]\n",
      " [3.21148399e+00 4.10968868e+00 9.32364816e+00]\n",
      " [2.56662735e+00 6.91333348e+00 3.78790083e-01]\n",
      " [2.27166141e+00 8.30469351e+00 7.08670597e+00]\n",
      " [3.69521214e+00 1.34649689e-01 9.68358498e+00]]\n"
     ]
    }
   ],
   "source": [
    "# Build random list of points\n",
    "points = np.random.rand(20,3) * 10\n",
    "print(points)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Points inside:\n",
      "[False  True  True  True  True  True  True  True  True  True  True  True\n",
      "  True  True False  True  True  True  True False]\n",
      "Points outside:\n",
      "[ True False False False False False False False False False False False\n",
      " False False  True False False False False  True]\n"
     ]
    }
   ],
   "source": [
    "print('Points inside:')\n",
    "print(box.inside(points))\n",
    "print('Points outside:')\n",
    "print(box.outside(points))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
